// 面试题 1: 赋值运算符函数
// 题目：如下为类型 CMyString 的声明，请为该类型添加赋值运算符函数。
// 考点：在实现赋值操作符函数时，如何处理内存分配失败的情况。备注：先分配内存，然后才销毁原内存。
#include <cstring>
#include <cassert>

class CMyString
{
public:
    CMyString(const char *pData = nullptr);
    CMyString(const CMyString &str);
    ~CMyString();

    CMyString& operator=(const CMyString &str);

    bool Check(const char *pData);
    bool Check(const CMyString &str);

private:
    char *m_pData;
};

CMyString::CMyString(const char *pData)
{
    if (pData == nullptr)
    {
        m_pData = new char[1];
        *m_pData = '\0';
    }
    else
    {
        int length = strlen(pData);
        m_pData = new char[length + 1];
        strcpy(m_pData, pData);
    }
}

CMyString::CMyString(const CMyString &str)
{
    int length = strlen(str.m_pData);
    m_pData = new char[length + 1];
    strcpy(m_pData, str.m_pData);
}

CMyString::~CMyString()
{
    delete[] m_pData;
}

CMyString& CMyString::operator=(const CMyString &str)
{
    if (this == &str)
        return *this;

    // p27 指出需要考虑内存分配失败抛出异常，所以先分配新内存，再释放旧内存
    int length = strlen(str.m_pData);
    char *p = new char[length + 1];

    delete[] m_pData;
    m_pData = nullptr;

    m_pData = p;
    strcpy(m_pData, str.m_pData);

    return *this;
}

bool CMyString::Check(const CMyString &str)
{
    if (m_pData == str.m_pData)
        return false;
    return strcmp(m_pData, str.m_pData) == 0;
}

bool CMyString::Check(const char *pData)
{
    return strcmp(m_pData, pData) == 0;
}

// 测试基础功能
void Test1()
{
    const char *text = "hello world";
    CMyString str1(text);
    CMyString str2;

    str2 = str1;
    assert(str2.Check(str1));
}

// 测试赋值给自己
void Test2()
{
    const char *text = "hello, world";
    CMyString str1(text);
    
    str1 = str1;
    assert(str1.Check(text));
}

// 测试连续赋值
void Test3()
{
    const char *text = "hello, world";
    CMyString str1(text);
    CMyString str2, str3;

    str3 = str2 = str1;
    assert(str3.Check(str1));
    assert(str2.Check(str1));
}

int main()
{
    Test1();
    Test2();
    Test3();
}

